## Teach Yourself ActiveX in 21 Days

- Introduction
- Overview
  - What is the File Transfer Protocol (FTP)?
  - The Gopher Protocol
  - HTTP and HTML
  - FTP and Gopher in the Future
- How Does the WinInet API Fit In?
  - The API Functions
- The MFC Classes and WinInet
  - Programming with MFC
  - The First Example Program
  - CInternetSession
  - CInternetConnection and the Connection Classes
  - The CFtpConnection Class
  - The FTP Sample Application
- Summary
- Q&A
- Workshop
- Quiz

#
— 13 —

##
Learning to Use the Win32 Internet API Library

###
Introduction

The Win32 Internet API is designed to handle the client side of the Internet connection. A familiar application that uses client-side technology is your browser. Unlike the ISAPI Server API, the Internet API (also know as WinInet) can be used in any normal application. The executable file does not have to be placed in a special directory with special permissions. In this chapter, you will learn the general functionality offered by this WinInet API and learn how to use the Microsoft programming classes to use this WinInet API.

###
Overview

Using the Internet requires a connection from a client (your browser, for example) to a server. The API supports a connection that can be a request to a server that understands HTTP, FTP, or Gopher. While there are other kinds of Internet connections, these three are currently the most widely used. Each kind of connection has a different but similar use.

####
What is the File Transfer Protocol (FTP)?

FTP is a File Transfer Protocol. It allows servers to make files available to clients, and it lets the client give the server files. It transfers files from one computer to another, regardless of the operating system on either machine. This was important because operating systems that didn't know how to talk to each other could use the FTP service to place or get files to each other. For example, a student in Texas using a Macintosh computer could retrieve or put files on a UNIX machine in California. FTP files are generally laid out in a tree structure, just like a directory system. This allows the client to place or retrieve files from the appropriate location.

In the Windows NT and Windows 95 operating systems, FTP commands are supported at the command prompt. The Microsoft Internet Explorer (Microsoft's browser) support for FTP is built in the address box. It can be accessed by typing FTP://ftp.server-name.

Figure 13.1. This is how Microsoft Internet Explorer displays an FTP site.

Figure 13.1 is an example of an FTP site. Notice the name and explanation of the site. They appear to use HTML, but in fact it is Internet Explorer doing the formatting. Look at how the files list the date and time of last modification as well as the file size. The directories are also listed. When using FTP, you have to know what file you are looking for and where to find it. There is no searching capability.

####
The Gopher Protocol

Compared to FTP, Gopher offers a little more to the client but also requires more of the server. FTP does not have any ability to jump from one server to another, but Gopher and HTTP do have the ability to jump to other servers using links. Gopher also offers the ability to annotate files and directories, and create custom menus. However, it does not allow the client to place files on the server.

Gopher servers have a tag file. This tag file keeps the name of the file the directory system uses: a "friendly" name that would be useful to the client (the administrator's name, modification date, and type of file, such as a text file or binary executable file). An example of a friendly name would be ‘The 1996 Acme Stock Report’, where the file name is actually ‘1996stpt.txt’. The client doesn't see the tag file, but information in the tag file can be sent back to the client along with the file itself. The tag file has to be constructed by an administrator of the Gopher site. The Microsoft Internet Information Server uses the command line application GDSSET.EXE to make tag files for the Gopher server it supports. A tag file would have to be built for each file retrievable by Gopher.

Gopher allows searches through the Wide Area Information Search (WAIS) index searching. WAIS is a full-text information retrieval system. In order for the file to be searchable, the server administrator has to create a WAIS index.

The Microsoft Internet Explorer's (Microsoft's browser) support for Gopher is built in the address box. It can be access by typing Gopher://gopher.server-name.

Figure 13.2. This is how Microsoft Internet Explorer displays a Gopher site.

Figure 13.2 is an example of a Gopher site. Notice the name and explanation of the site. This page appears to use HTML, but in fact it is Internet Explorer doing the formatting. This site offers directories and searches to clients. The Gopher server differentiates between files, directories, and searches. This particular Gopher site doesn't have any files at the root directory, but it does have several directories and searches.

Figure 13.3. This is how a Gopher site searches an index, as presented through Microsoft Internet Explorer.

Figure 13.4. This is a Gopher site's search results, based on the search from Figure 13.3. The search results let the client know where to go in the Gopher file system to find the file.

The Gopher search capabilities are not as advanced as some of the searches that are now available through HTTP/HTML, but the Gopher search was a good resource in its time.

####
HTTP and HTML

Both FTP and Gopher offer useful services, but they lack of few qualities. Both are basically file systems with only files and searches to offer. To see the information, the client must download the file to his computer and open it with the correct application. HTTP and HTML offer the client the information without having to open the file. Actually, the concept choosing files is replaced with the concept of moving to other pages. At this point in the book, you should know how to move between pages in your browser.

HTTP servers offer much more to a client. While FTP and Gopher are file server systems, HTTP can be a complete server system. It can offer unlimited capabilities such as database access, true search engines, and calculations. The list is only limited by your imagination. The HTTP server does its work and then sends the client's browser a file to display the result of whatever work it was requested to do.

The HTTP server’s work is far more versatile than FTP and Gopher because it can act on the request. An example (one of many) is the request for information, such as the Yellow Pages on the Web. The request goes from your browser to the server. The server can filter the request for valid data or passwords. If the request is invalid, the server returns an HTML page notifying you. If the request is valid, the server can look through a file server, look through an email server, look through a database, or do just about anything else.

####
FTP and Gopher in the Future

The services offered by FTP and Gopher are quickly being replaced by Web pages served up by HTTP and written in HTML. If you search for Gopher or FTP pages, you are probably using a search engine behind an HTML form. Why would someone keep these servers around? Converting an existing (and probably extensive) server to HTML is not hard, but there are several costs involved. These costs can involve hardware, software, labor, training, and administration of the new system. Many of these systems reside in governments or schools, and the resources to update the systems are not available.

HTML doesn't solve every problem either. The ability for a client to place a file on a server (as FTP can do) is not allowed. The Microsoft Internet Information Server comes with all three services.

###
How Does the WinInet API Fit In?

The WinInet API is designed to allow applications access to Internet (or intranet) information, without requiring detailed knowledge of how the connection works (such as TCP/IP or sockets). The API makes reading a file from the Internet as easy as reading a file from your hard drive. If you are familiar with other Win32 APIs then the buffer and error handling of this API should look familiar. If you want to have all the detailed information of the WinInet specification, you can find the document at http://www.microsoft.com/intdev/sdk/docs/wininet/.

The difficulty with Internet technology is that it changes very quickly. Who wants to learn a set of functions that will soon be obsolete? The WinInet API is written to flexibly change the underlying technology and yet have a consistent set of functions for programmers to use.

Microsoft has written a set of classes that incorporate the WinInet API functionality into the Microsoft Foundation Class (MFC) classes. The benefit of these classes is that they fit nicely into the MFC hierarchy of classes, thereby giving the programmer more functionality than just what the WinInet API functions can afford. If you are familiar with MFC, learning these new classes will be a snap. In order to use these classes, you have to use the Microsoft Visual C++ version 4.2. Prior versions of Visual C++ will not have these classes.

####
The API Functions

Before looking at the MFC classes, let's first take a look at the functions in the WinInet API. The main functions a client should be concerned with are connecting to the server, having the server do something, and closing the connection to the server.

Please check to see if the hardware and software in your operating system are correctly configured before you begin programming with this API. Connecting to a Web site with your browser would be a good test of whether your machine's hardware and software are working correctly. This API takes advantage of the software you already have installed on your system. So instead of having to install the protocols and software to use this API, the API assumes that you already have connectivity with these three protocols.

While there are only three technologies supported by the API, there are several functions that you need to accomplish regardless of which protocol you use. The general functions are:

- InternetOpen—is the first function you will need to call. It initializes the WinInet API. Without this function call, the results could be unpredictable.
- InternetOpenUrl—makes a connection to the server and prepares for the information to be retrieved.
- InternetCrackUrl—parses a URL string into components such as server name, path in server, user name, password, and any parameters.
- InternetCreateUrl—creates a URL string from components such as server name, path in server, user name, password, and any parameters.
- InternetCanonicalizeUrl—converts a URL string into a ‘safe’ form. This safe form can include replacing invalid characters, converting characters to other characters, and encoding.
- InternetCombineUrl—combines the base and path of a URL into a single string which will be made ‘safe’ by canonicalizing the URL.
- InternetConnect—begins a session for any protocol to make a connection. The session information can include server name, user name, password, connection protocol (HTTP, FTP, Gopher). You do not need to open a session for each request. A single session can handle all your requests. You need to balance the session per request for your particular use.
- InternetQueryOption—returns information about your internet session such as user name, password, time out features, asynchronous features, callback features, and other security features.
- InternetSetOption—sets information about your internet session such as user name, password, time out features, asynchronous features, callback features, and other security features.
- InternetErrorDlg—displays message box for error occurring from the HttpSendRequest error conditions. The dialog displays the error message and gives the button options of OK, CANCEL or RETRY.
- InternetCloseHandle—is used to terminate an Internet handle and free any associated resources. If the handle is a parent of other handles, this function can be used to close all the child handles of the parent. This function closes the handle opened by InternetOpen.
- InternetReadFile—reads a buffer of data. InternetOpenUrl, FtpOpenFile, GopherOpenFile, and HttpOpenRequest will create the buffer. Make sure your buffer size if large enough for requested information. If the requested information is not available (i.e. this function is waiting on the server), the function will not return until the information is available.
- InternetSetFilePointer— moves the position of the file pointer by a number of bytes. You can move the position relative to the file pointer’s current position, the beginning of the file, or the end of the file.
- InternetWriteFile—writes a number of bytes to a file and returns the number of bytes written. It is useful to know how many bytes were actually written to a file if (for some reason), the function could not write all the bytes.
- InternetFindNextFile—finds the next file where the first file was found with either FtpFindFirstFile or GopherFindFirstFile.
- InternetSetStatusCallback—sets the function address to call when there is status information. This function address is of a function you write. This function would do something meaning with the status information, such as let the user know what the status is.
- InternetConfirmZoneCrossing—lets the user know if he is moving from a secured web page to an unsecured web page.
- InternetTimeFromSystemTime—formats the date and time from a specified HTTP format (as noted in the HTTP specification) to a string.
- InternetTimeToSystemTime—formats a string into a specified HTTP format (as noted in the HTTP specification).
- InternetAttemptConnect—lets the client attempt to connect to the server before a file request is attempted. The request of connecting is shorter than connecting and requesting a file.

> > Note
> > So what does URL stand for? URL stands for universal resource locator. In terms of the Internet, that would be the server name, such as www.microsoft.com.

> > Note
> > SYSTEMTIME is a data structure that contains the following information: year, month, day of week (where Sunday is 0), day of month, hour, minute, second, and millisecond.

To get to specific files or other information, you will have to use the functions that coincide with your particular need. There are functions specific to each of the three connections supported: HTTP, FTP, and Gopher.

The HTTP functions are

- HttpOpenRequest—creates a handle to an HTTP server by setting the type of action (such as GET), the object of that action (file, ISAPI filter, template, etc.), the object making the request (generally the web page), and the type of data you can accept (such as text).
- HttpAddRequestHeaders—adds or removes information to the handle created by HttpOpenRequest. This information is in the form of headers. In general, a web browser will send information about itself such as manufacturer and version of product. Web servers can act on this information as well as log this information.
- HttpSendRequest—sends the request created in HttpOpenRequest and HttpAddRequestHeaders to the server. This function also always you to specify additional headers.
- HttpQueryInfo—returns information about the sent header (you created), returned header (server created) or the returned request (server created). The last two pieces are probably more interesting. The header information is important because it can tell you things like when was the file last modified, when the file expires, what format type is the returned request, etc.

The FTP functions include the following:

- FtpFindFirstFile—can find either the first file or the first directory on the FTP server starting at a specified path. You can only call this function once per FTP session, any other calls will be a waste of your time. To find more files or directories, you need to use the InternetFindNextFile function. The FTP protocol can not guarantee correct file information such as create date and time, so it returns the most accurate information based on available information.
- FtpGetFile—retrieves a file from the FTP server and puts it on your local system. You can control where the file goes, what the new file name is, what the new file attributes are, and other conditions of the file transfer.
- FtpPutFile—sends a file to the FTP server and puts it in a specific directory that you choose. You must have appropriate permissions for this function to succeed.
- FtpDeleteFile—deletes a file from the FTP server. You must have appropriate permissions for this function to succeed.
- FtpRenameFile—renames a file on the FTP server. You must have appropriate permissions for this function to succeed.
- FtpOpenFile—opens a file on the FTP server for reading or writing. You want to use this function if you need to control how the data is sent to the server or read from the server. This function gives you a more granular control over the process.
- FtpCreateDirectory—creates a directory on the FTP server. You must have appropriate permissions to use this function.
- FtpRemoveDirectory—deletes a directory on the FTP server. You must have appropriate permissions to use this function.
- FtpSetCurrentDirectory—changes the current directory. You should find out where you are by using FtpGetCurrentDirectory.
- FtpGetCurrentDirectory—gives you the name of the current FTP server directory you are in.

The Gopher functions include the following:

- GopherFindFirstFile— can find the first file based on a Gopher locater, an indexed search, or the top level information in the Gopher server. After the first call to GopherFindFirstFile, any other calls to find files should use the InternetFindNextFile function.
- GopherOpenFile—starts reading a Gopher file.
- GopherCreateLocator—creates a locator string. Information necessary to create a locator string includes server name, friendly name of file, and file name.
- GopherGetAttribute—returns information about the file on the Gopher server.

Notice that once you get the files enumerated, based on your connection type, the rest of the enumeration is used with InternetFindNextFile.

Examples of function calls it would take to download from an HTTP server include

- InternetOpen
- InternetConnect
- HTTPOpenRequest
- HTTPSendRequest
- InternetReadFile
- InternetCloseHandle

###
The MFC Classes and WinInet

If a programmer wanted to write an application using this API, a lot of programming would be required to handle non-WinInet aspects of the application, such as the graphical user interface (GUI), any database connectivity, and just about anything else the application needs to do. You could write a WinInet program without MFC (or some other programming class library), but for rapid application development (RAD), this is probably unrealistic. Knowledge of C++ class usage is mandatory for using these classes.

The MFC classes that work with this functionality are

- CInternetSession—creates and initializes the internet session you need, regardless of the protocol you are using.
- CInternetConnection—is the base class for all three protocol connection types. This class manages the common functionality and low-level details of the connection.
- CFtpConnection—is used to connect to an FTP server. This class handles most of the directory and file tasks.
- CGopherConnection—is used to connect to a Gopher server. This class handles the locator and attribute information.
- CHttpConnection—is used to connect to an HTTP server. This class hanldes the intial request to the server.
- CInternetFile—inherits from CStdioFile and is the base class for CGopherFile and CHttpFile. This base class handles the file manipulation for the Gopher and Http protocol.s
- CGopherFile—is needed to handle Gopher files but doesn’t have very much functionality. It’s only methods are the contructor and Close().
- CHttpFile—is needed to handle Http files. It will send the request to the Http server, read the headers that the server sends back and the html data stream that the server sends back.
- CFileFind—is the base class for CGopherFindFile and CFtpFindFile. It handles file searches and file information.
- CFtpFileFind—finds FTP files on an FTP server.
- CGopherFileFind—finds the Gopher files on the Gopher server and returns information about information in the tag file.
- CGopherLocator—create the locator object to access Gopher files.
- CInternetException—handles Internet programming exceptions.

Global functions for the WinInet in MFC include the following:

- AfxParseURL—tells you what kind of protocol server, file, port and what type of protocol the URL will go to: HTTP, FTP or Gopher.
- AfxGetInternetHandleType—returns the type of HTTP, FTP or Gopher request handle you have such as finding a file versus connecting to a server.
- AfxThrowInternetException—throws a memory exception, such as a call to memory allocation fails.

####
Programming with MFC

In order to follow the code snippets and exercises in the rest of the chapter, you need to make sure that the Internet connectivity to HTTP and FTP is working. You can use your browser to verify this. You also need to have Microsoft Visual C++ version 4.2 or later installed. The help files and sample application of Microsoft Visual C++ go into great detail about what these new classes do. Please see these resources for additional information.

####
The First Example Program

This first example program will connect to a HTTP server and read the HTML file (default.htm). As it reads the file, the application will print the information to a screen. This is not a sophisticated program, but you will actually connect to a server and read a file. There are three types of operations you will be doing. You will open a connection to the server, make a request of the server, and read a file. As you go through this example, look for the differences between these three pieces.

You will need to find a Web server that has a Web page in the root directory to exchange for the names I use in this example. In the example code, I chose a server I could get to at the time this chapter was written. The danger in this is that the server might not be working now. Before you begin, you need to find a Web server (any will do) that has the default.htm document. Some of the more advanced servers don't have this file. As long as you know the name of a server and the name of a file in the root directory of that server, you can exchange those names for the ones I use in the code.

In order to start, let's create an application. Open up Microsoft Visual C++, and make a new project workspace. Name the workspace HTTPexam. Make sure the project is a console application. The reason it should be a console application is because I don't want you to be confused by seeing any classes that are not closely related to these WinInet classes. Because a console application doesn't use MFC by default, you need to change the project so that it does use MFC. In your project, change your project settings (Build Menu/Settings) to use MFC in a shared dll (General Tab/MFC drop-down list). If you don't let the project know you need to use the MFC dll, when you build, you will get linker errors regarding beginthread and endthread functions.

> > Note
> > A console application is a DOS-type application where there are no windows.

Create a header file httpex.h that looks like Listing 13.1.

Listing 13.1. httpex.h (create a header file).

    #include <afx.h> // header file for MFC
    #include <afxinet.h> // header file for WinInet
    #include <iostream.h> // header file for input/output stream
    #include <stdlib.h> // header file for standard library functions
    class CHttpExample : public CInternetSession
    {
    public:
     CHttpExample(LPCTSTR pszAppName, int nMethod);
    };

Create a code file httpex.cpp that looks like Listing 13.2.

Listing 13.2. httpex.cpp (write bare application).

    #include "httpex.h" // header file for Project
    // CHttpExample class implementation
    void main()
    {
    // variables
    // running code implementation
    }

Make sure httpex.cpp has been added to the project files, and update project dependencies. The CHttpExample class's only base class is CInternetSession. The derived class you made (CHttpExample) only has one method. You don't need anything more in your header file to make a connection and to retrieve information from a server.

Now let's add the implementation code that is associated with the function defined in the header file. Add Listing 13.3 to httpex.cpp after the line //CHttpExample class implementation.

Listing 13.3. httpex.cpp (add class implementation code).

    CHttpExample::CHttpExample(LPCTSTR pszAppName, int nMethod)
     : CInternetSession(pszAppName, 1, nMethod)
    {
    }

There is no code in the constructor for your CHttpExample class because the base class does everything you need. All you have to do is pass this information to it when you declare a variable of CHttpExample type.

At this point, the project should build with no errors or warnings. If it does have errors or warnings, now is a good time to fix your project settings and debug your code. However, the main function is still empty, so the program will do nothing. Let's add some useful code to make the program do something.

You need to declare a few variables that you want to work with. The first and most obvious is to instantiate your class by having a variable of CHttpExample type. The second variable you need is for your connection type and will be of type CHttpConnection. The third variable you need will help you read the file and will need to be of type CHttpFile. You also need to add a few character strings to handle the server name, filename, header information you send, header information you request, and the text of the file in which you are interested. The last variables will hold the status of functions you are executing. Add Listing 13.4 below the line with // variables on it.

Listing 13.4. httpex.cpp (declare variables).

    CHttpExample session(_T("Http Example"), INTERNET_OPEN_TYPE_PRECONFIG);
    CHttpConnection* pServer=NULL;
    CHttpFile* pFile=NULL;
    CString serverName(_T("dinaf2"));
    CString fileName(_T("/default.htm"));
    CString headerInfo(_T("Accept: text/*\r\nUser-Agent: HTTP Example\r\n"));
    CString newLocation;
    CString returnedFileText;
    DWORD dwReturnCode;
    BOOL fSuccess;

> > Tip
> > You may be asking what the _T("string") syntax does. By using the _T macro, I can compile my code as Unicode, MultiByteCharacterSet, or ANSI (single-byte character set) without having to change the way I have my hard-coded strings. The CString class handles how the string is kept based on which type of string I am interested in. In order to compile your code in a particular setting, make sure you have one of the following if defined in your project settings: _UNICODE, _MBCS, or _SBCS. If you plan to have your code used outside the English language, this is important.

The way you declared the session variable will pass the information from the CHttpExample class to the CInternetSession class. A CString can be either initialized when it is declared or later. Both methods are used here. The two variables pServer and pFile will be initialized in the code. Also notice that the server does not have to be prefixed with the http://. If you did prefix the name, a connection would not be established.

The second parameter to the constructor for your session variable is the type of Internet access you want. This has nothing to do with the server you are trying to get to. This parameter tells the software how to configure our machine's side of the connection. You have three choices here. I chose the one that will work with my machine. If you are not running on a Windows NT or Windows 95 operating system, you will have to choose the flag that is best for you. The three flags are

- INTERNET_OPEN_TYPE_PRECONFIG—means the access information is preconfigured in your operating system's registry. (This is a safe choice for WinNT and Win95.)
- INTERNET_OPEN_TYPE_DIRECT—means direct access to the Internet.
- INTERNET_OPEN_TYPE_PROXY—means access through a proxy or gateway. For corporate situations, this might be what you need.

If you do not know what type of access you have, you will need to contact your system administrator or Internet service provider (ISP).

Now let's write some code to get you connected. Add Listing 13.5 to your main function just below the // running code implementation line.

Listing 13.5. httpex.cpp (add connection and request code).

    pServer = session.GetHttpConnection(serverName);
    pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
     fileName,NULL,1,NULL,NULL,INTERNET_FLAG_EXISTING_CONNECT);
    // connection to server
    pFile->Close();
    if(pFile)
     delete pFile;
    pServer->Close();
    if(pServer)
     delete pServer;
    session.Close();

Let's look at each line of code. The first line of code initializes your connection to the name of the HTTP server and returns a pointer to a CHttpConnection object. But what if the server had some sort of security? The code didn't pass a username or password, so a secured connection would fail. The function parameters for GetHttpConnection are (serverName,portNumber,userName,password). But because I'm using the default system registry, I don't need to set the port number. The function definition defaults this to INTERNET_INVALID_PORT_NUMBER. The username and password also default to NULL so if I don't need them, I don't need to pass them as parameters. If a connection to the server could not be established, the pServer pointer would be null. It is a good idea to check that the pointer is not null before continuing; however, I don't do that here. Any a real-world program, you would want to check the pointer before proceeding. This will save you from possible exceptions in your code.

The second line of code requests the file default.htm from the server. The first parameter CHttpExample::HTTP_VERB_GET tells the server what kind of request you are making of it. If you pass this parameter as NULL, the HTTP_VERB_GET is used. The other choices correspond with normal requests that can be made to a Web server:

- HTTP_VERB_POST = 0
- HTTP_VERB_GET = 1
- HTTP_VERB_HEAD = 2
- HTTP_VERB_PUT = 3
- HTTP_VERB_LINK = 4
- HTTP_VERB_DELETE = 5
- HTTP_VERB_UNLINK = 6

The object or filename you are interested in is the second parameter. The rest of the parameters take default values, but to let you know what they are I included them in the function call. The other parameters handle issues such as what type of file you can accept (text-only is an example), what the URL address of the object is (if the object is not in the Web's root directory), and how you want to handle the file returned (don't cache, make it secure with encryption, and so on).

The last few lines of code close the connection to the server and gracefully close down your CInternetSession object. You should be able to build and run the code. The application at this point connects to the server, requests the file, and then closes down. In order to look at the file, you need to add more code. Insert Listing 13.6 just below the line //connection to server.

Listing 13.6. httpex.cpp (add file handling code).

    if(fSuccess = pFile->AddRequestHeaders(headerInfo))
    {
     if(fSuccess = pFile->SendRequest())
     {
     if(fSuccess = pFile->QueryInfoStatusCode(dwReturnCode))
     {
     if(dwReturnCode==200)
     {
     if(fSuccess = pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_
     [cc:icc]CRLF,newLocation))
     {
     if(newLocation != _T(""))
     cout << _T("Header Info: ") << newLocation
     [cc:icc]<< endl << endl;
     }
     pFile->SetReadBufferSize(2000);
     while(pFile->ReadString(returnedFileText))
     cout << returnedFileText;
     }
     }
     }
    }

You have now written the entire application to read an HTML file and write it to the screen. Let's look at the code from Listing 13.6 in detail.

The first line adds information to the header you send to the server. You would use this if you wanted control over the exact request sent to the server. Our CString variable headerInfo tells the server you accept text information, and it tells the server the name of the application making the request. If the function fails, it returns a 0 into fSuccess. You need to check every function that returns a success code before continuing.

The second line sends the request. The function is empty because you have already set the filename and location. However, if you were executing a CGI script or ISAPI filter on the server, this is the function you would pass the information to. This information could include the name of the script and parameters to that script.

The next line returns information on how well our request was satisfied. This is important because if there was a problem, you would need to find out why. The return code dwReturnCode will be a number representing that success or failure. In the code, I only check for 200 (the request was fulfilled without any errors) because that means my request was satisfied. The return codes are broken down in Table 13.1.

Table 13.1 Return codes.

Return Code | Meaning
200 | Request completed.
201 | Object created, reason = new URI.
202 | Asynchronous completion.
203 | Partial completion.
204 | No information to return.
300 | Server couldn't decide what to return.
301 | Object permanently moved.
302 | Object temporarily moved.
303 | Redirection w/ new access method.
304 | If-modified-since was not modified.
400 | Invalid syntax.
401 | Access denied.
402 | Payment required.
403 | Request forbidden.
404 | Object not found.
405 | Method is not allowed.
406 | No response acceptable to client found.
407 | Proxy authentication required.
408 | Server timed out waiting for request.
409 | User should resubmit with more information.
410 | The resource is no longer available.
411 | Couldn't authorize client.
500 | Internal server error.
501 | Required not supported.
502 | Error response received from gateway.
503 | Temporarily overloaded.
504 | Request timed out waiting for gateway to respond.

The next line of code in Listing 13.6 uses the QueryInfo method from the CHttpFile class. This method retrieves information from the header that was returned from the server. The server can supply you with different kinds of information that may be useful to a client application. The complete list is

- HTTP_QUERY_MIME_VERSION
- HTTP_QUERY_CONTENT_TYPE
- HTTP_QUERY_CONTENT_TRANSFER_ENCODING
- HTTP_QUERY_CONTENT_ID
- HTTP_QUERY_CONTENT_DESCRIPTION
- HTTP_QUERY_CONTENT_LENGTH
- HTTP_QUERY_ALLOWED_METHODS
- HTTP_QUERY_PUBLIC_METHODS
- HTTP_QUERY_DATE
- HTTP_QUERY_EXPIRES
- HTTP_QUERY_LAST_MODIFIED
- HTTP_QUERY_MESSAGE_ID
- HTTP_QUERY_URI
- HTTP_QUERY_DERIVED_FROM
- HTTP_QUERY_LANGUAGE
- HTTP_QUERY_COST
- HTTP_QUERY_WWW_LINK
- HTTP_QUERY_PRAGMA
- HTTP_QUERY_VERSION
- HTTP_QUERY_STATUS_CODE
- HTTP_QUERY_STATUS_TEXT
- HTTP_QUERY_RAW_HEADERS
- HTTP_QUERY_RAW_HEADERS_CRLF

The last two methods of code to discuss are the SetReadBufferSize and ReadString. The SetReadBufferSize lets MFC know how large a buffer of information you want each time you look at the file. ReadString reads the number of bytes you specified in SetReadBufferSize.

> > Tip
> > The default for the buffer, if you choose not to call SetReadBufferSize, is 4096 bytes. Do not depend on CStrings to manage the size of your buffer. I suggest that you always set your buffer size.
> > The buffer size is in bytes. If your character type is larger than 1 byte, remember to increase the size of the buffer to accommodate the character size. Consider an example of a UNICODE character. Assuming the UNICODE character is two bytes, and that our string is 2000 characters, the math would be (2 * 2000 = total buffer size needed).

In this example the program connected to a server, read a file and header information returned from the server, and printed to the screen. Figure 13.5 is a screen shot of this application. Notice the header information and then the body of the HTML. The HTML isn't formatted because the ReadString method doesn't know or care about formatting.

Figure 13.5. The HTTP example application output.

It seems like there is a lot of work put into this example, but the code has so few lines. The MFC class inheritance provides the power behind the code. Let's take a closer look.

####
CInternetSession

The program only used three functions from the CInternetSession class in the HTTP example: the constructor, GetHttpConnection, and Close. This class is flexible enough to handle all three connection types, set any options, and handle any call backs. CInternetSession inherits from the MFC's CObject class. The CObject class has nothing to do with the Internet, but it does have the methods necessary for memory allocation, debugging, and serialization including new, delete, and the equals operator (=). These are basic functions, but they are helpful here because you don't have to write them yourself.

####
CInternetConnection and the Connection Classes

CInternetConnection is the base class for CHttpConnection, CFtpConnection, and CGopherConnection. It provides methods to get the server name, server context number, and session object. The CHttpConnection class doesn't do much more. It only has two methods: a constructor and OpenRequest. The same is true for the CGopherConnection class. These classes don't need many functions because most of the work is done on the server.

Why would a programmer write an application for HTTP or Gopher when they probably already have a Web browser or Gopher reader? There are a variety of reasons, only limited by your needs. The interesting capabilities of these classes are not getting a file to display the information as a browser would. However, if that is what you want to do, go for it. Imagine you are a Web site administrator and you need to check all the links on your pages to see if those pages, images, audio files, and so on are working. You could write a program to anaylize the links on each page. You could do this by finding the reference to the file and then attempting to retrieve that file. If you can't get the file, neither can your browser. Another example is that many Web sites want the current information on their Web pages to be attractive. It would be easy to write a program that lists all files that have not been modified in the last 30 days. These applications can be anywhere, not necessarily on the Web server.

####
The CFtpConnection Class

Although the classes for HTTP and Gopher do not have many methods, the CFtpConnection class does because the client has more control and choices about what he does on the server when he uses FTP. He can create or delete files and directories. This is a powerful class because it allows greater flexibility that can be controlled.

Imagine you know you will need every file and subdirectory underneath the \computer-club directory. With a browser such as Microsoft Internet Explorer, you would just have to click on each subdirectory and pull down each file. Wouldn't it be nice if you could start one program and then go onto more interesting things? When the program is finished, the files would appear on your hard drive just as they appeared on the server. This would save you the time and the trouble of having to do it yourself. Your program could even check to see if you had enough space on your hard drive before bringing down each file.

####
The FTP Sample Application

This sample application will connect to an FTP server, read all the files and directories in the root, and get a file named Welcome.txt. The output of the application should look something like Figure 13.6.

Figure 13.6. The FTP sample application output. The URL of the location is included.

As with the previous example, you will need to find an FTP server and a file you want to retrieve from that server. If you have permissions to write to that server, try to put a file on the server instead of getting a file.

In order to start, first create an application. We need to create the application in the same manner as the previous example. Open up Microsoft Visual C++, and make a new project workspace. Name the workspace FTPexam. Make sure the project is a console application. The reason it is a console application is that I don't want you to be confused by seeing any classes that are not closely related to these WinInet classes. Because a console application doesn't use MFC by default, you need to change the project so that it does use MFC. In your project, change your project settings (Build Menu/Settings) to use MFC in a shared dll (General Tab/MFC drop-down list). If you don't let the project know you need to use the MFC dll, when you build, you will get linker errors regarding beginthread and endthread functions.

Because you have already written one application, enter all the code for the second application. The general flow of the application should make sense to you.

Create a header file ftpex.h that looks like Listing 13.7

Listing 13.7. ftpex.h (create header file).

    #include <afx.h> // header file for MFC
    #include <afxinet.h> // header file for WinInet
    #include <iostream.h> // header file for input/output stream
    #include <stdlib.h> // header file for standard library functions
    class CFtpExample : public CInternetSession
    {
    public:
     CFtpExample(LPCTSTR pszAppName, int nMethod);
    };

Create a code file ftpex.cpp that looks like Listing 13.8.

Listing 13.8. ftpex.cpp (write the entire application).

    #include "ftpex.h" // header file for Project
    // CFtpExample class implementation
    CFtpExample::CFtpExample(LPCTSTR pszAppName, int nMethod)
     : CInternetSession(pszAppName, 1, nMethod)
    {
    }
    void main()
    {
    // variables
    CFtpExample session(_T("Ftp Example"), INTERNET_OPEN_TYPE_PRECONFIG);
    CFtpConnection* pServer=NULL;
    CString serverName(_T("dinaf2"));
    CString fileName;
    CString subdirectoryName;
    CString currentDirectory;
    BOOL fSuccess;
    // running code implementation
    pServer = session.GetFtpConnection(serverName);
     if(fSuccess = pServer->GetCurrentDirectoryAsURL(currentDirectory))
     {
     cout << _T("Connected to ") << currentDirectory << endl << endl;
     CFtpFileFind ftpFind(pServer);
     if(fSuccess = ftpFind.FindFile(_T("/*")))
     {
     while(fSuccess)
     {
     fSuccess = ftpFind.FindNextFile();
     if(ftpFind.IsDirectory())
     {
     fileName = ftpFind.GetFileName();
     cout << _T("directory: ") << fileName << endl;
     }
     else
     {
     fileName = ftpFind.GetFileName();
     if(fileName==_T("Welcome.txt"))
     {
     if(fSuccess = pServer->GetFile(fileName,fileName,TRUE,
     FILE_ATTRIBUTE_NORMAL,FTP_TRANSFER_TYPE_ASCII))
     cout << _T(" retrieved") << endl;
     else
     cout << endl;
     }
     else
     cout << endl;
     }
     }
     ftpFind.Close();
     }
     else
     {
     ftpFind.Close();
     }
     }
    pServer->Close();
    if(pServer)
     delete pServer;
    session.Close();
    }

The connection code is very similar to the HTTP example's connection code. The major differences between this example and the previous one are the use of CFtpFindFile and the methods used from CFtpConnection.

The CFtpConnection class has quite a few functions for manipulating where the client is and what the client is doing on the server. The methods of CFTPConnection are

- CFtpConnection—is the class constructor. All general initialization of class members happens here.
- SetCurrentDirectory—sets the current directory for this connection.
- GetCurrentDirectory—gets the current directory for this connection.
- GetCurrentDirectoryAsURL—gets the current directory in relation to the root of server, and includes the server's name.
- RemoveDirectory—removes the directory from the server.
- CreateDirectory—creates the directory on the server.
- Rename—renames a file on the server.
- Remove—removes a file on the server.
- PutFile—puts the file on the server.
- GetFile—gets the file from the server.
- OpenFile—opens the file.
- Close—closes the connection to the server.

Also notice that instead of using CInternetFile (as in the CHTTP example), you used the CFtpFindFile class. Its members are

- CFtpFileFind—is the class constructor. Any intialization of class members happens here.
- FindFile—finds a file on the FTP server.
- FindNextFile—Finds the next file.
- GetFileURL—Gets the URL of a file, including the path.

What about some of the functions we used to manipulate the file that are not in the preceding class method list for CFtpFindFile, such as IsDir? Because CFtpFindFile inherits from CFileFind, the codes get all the functionality of this base class. The class is used by the Gopher and FTP connection types. It gives the code some neat such as is the file really a directory or is the file marked with the read-only attribute, when was the last time the file was accessed, and how big is the file. These are just a few of our choices; the rest of the methods of CFileFind I'll leave for you to discover.

Notice that the GetFile function's first two parameters in Listing 13.8 were both fileName. The first variable defines the name of the file I want to retrieve and the second variable defines the file on the local hard drive I want. The fourth and fifth parameters are flags. The fourth parameter is what attributes we want the file to have on our hard drive. Your choices are

- FILE_ATTRIBUTE_ARCHIVE
- FILE_ATTRIBUTE_COMPRESSED
- FILE_ATTRIBUTE_DIRECTORY
- FILE_ATTRIBUTE_NORMAL
- FILE_ATTRIBUTE_HIDDEN
- FILE_ATTRIBUTE_READONLY
- FILE_ATTRIBUTE_SYSTEM
- FILE_ATTRIBUTE_TEMPORARY

The fifth parameter specifies the condition of the transfer of the file. Your choices are text or binary:

- FTP_TRANSFER_TYPE_ASCII
- FTP_TRANSFER_TYPE_BINARY

> > Tip
> > Use the FTP_TRANSFER_TYPE_BINARY when you want the file to be of the same type as it is stored on the server. This is also the default choice if you don't specify a type.

> > Tip
> > If you just want to read a file from an FTP server, you can use the CInternetFile::Read along with the CFtpConnection::OpenFile functions.

Listing 13. 9 displays the httpex.cpp file in its entirety.

Listing 13.9. The HTTP example (entire httpex.cpp file).

    #include "httpex.h" // header file for Project
    // CHttpExample class implementation
    CHttpExample::CHttpExample(LPCTSTR pszAppName, int nMethod)
     : CInternetSession(pszAppName, 1, nMethod)
    {
    }
    void main()
    {
    // variables
    CHttpExample session(_T("Http Example"), INTERNET_OPEN_TYPE_PRECONFIG);
    CHttpConnection* pServer=NULL;
    CHttpFile* pFile=NULL;
    CString serverName(_T("dinaf2"));
    CString fileName(_T("/default.htm"));
    CString headerInfo(_T("Accept: text/*\r\nUser-Agent: HTTP Example\r\n"));
    CString newLocation;
    CString returnedFileText;
    DWORD dwReturnCode;
    BOOL fSuccess;
    // running code implementation
    pServer = session.GetHttpConnection(serverName);
    pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
     fileName,NULL,1,NULL,NULL,INTERNET_FLAG_EXISTING_CONNECT);
    if(fSuccess = pFile->AddRequestHeaders(headerInfo))
    {
     if(fSuccess = pFile->SendRequest())
     {
     if(fSuccess = pFile->QueryInfoStatusCode(dwReturnCode))
     {
     if(dwReturnCode==200)
     {
     if(fSuccess = pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF,newLocation))
     {
     if(newLocation != _T(""))
     cout << _T("Header Info: ") << newLocation << endl << endl;
     }
     pFile->SetReadBufferSize(2000);
     while(pFile->ReadString(returnedFileText))
     cout << returnedFileText;
     }
     }
     }
    }
    // connection to server
    pFile->Close();
    if(pFile)
     delete pFile;
    pServer->Close();
    if(pServer)
     delete pServer;
    session.Close();
    }

###
Summary

In this chapter you learned about the Win32 Internet API and the MFC classes corresponding to this API. These functions allow the client to make a connection to a server. With these MFC classes, a programmer can make a connection to a server and manipulate files. The neat feature of these classes is that a programmer doesn't have to understand TCP/IP programming or any other low level functionality because they abstract and manipulate this work for you.

The HTTP classes help you get files from a Web server. The FTP classes let you do all the file and directory manipulation that an FTP server will allow. The Gopher classes cover a little of the other two classes.

###
Q&A

- Q Where do you download the Win32 API?
- A Download from http://www.microsoft.com/intdev/sdk/docs/wininet/
- Q What version of Microsoft Visual C++ do you need to use these cool classes?
- A Use version 4.2, which is only available through subscription.
- Q What is the base class for connecting to a server?
- A CInternetSession
- Q What is the base class for the three connection types?
- A CInternetConnection
- Q What class do you need to read an HTML file?
- A CHttpFile
- Q What classes do you need to read an FTP or a Gopher file?
- A CFtpFileFind and CGopherFileFind, respectively

###
Workshop

In your own browser, try to connect to an FTP site. You may have to change the options of your browser. Also try to connect to the FTP site through any commands supported by your operating system. Once you are connected, try downloading a file. If you have a Web server, configure it for FTP, connect to it, and put a file in its directory. Next, try to connect to a Gopher site. You may have to change the options of your browser. Also try to connect to the Gopher site through any commands supported by your operating system. Once you are connected, try downloading a file. If you have a Web server, configure it for Gopher, connect to it, and get a file from its directory. Try to use a search engine. Attempt to create a WAIS search on your Web server (if you have one).

###
Q uiz

1. Why will a normal console application not link with MFC, even if you have the proper #include?
2. What methods do I need to connect to a server?
3. Why do I have to check the return value from CFtpConnection::GetCurrentDirectory()?
4. What is the class I should use to handle an exception?
5. What is the _T macro used for?